package edu.luc.etl.jbunit;

import java.beans.BeanInfo;
import java.beans.EventSetDescriptor;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.EventListener;
import java.util.LinkedList;
import java.util.List;

public class EventRecorder {

  protected InvocationHandler handler = new InvocationHandler() {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println(method.toString() + Arrays.asList(args));
      return null;
    }
  }; 

  protected EventListener getListenerProxy(Class[] interfaces) {
    return (EventListener) Proxy.newProxyInstance(getClass().getClassLoader(), interfaces, handler);
  }
  
  public EventListener getListener(Class clazz) {
    return getListenerProxy(new Class[] { clazz });
  }

  protected EventListener getListener(Object source, BeanInfo beanInfo) {
    List<Class> interfaces = new LinkedList<Class>();
    for (EventSetDescriptor d : beanInfo.getEventSetDescriptors()) {
      interfaces.add(d.getListenerType());
    }
    return getListenerProxy((Class[]) interfaces.toArray(new Class[0]));
  }
  
  public EventListener getListener(Object source) throws IntrospectionException {
    return getListener(source, Introspector.getBeanInfo(source.getClass()));
  }
  
  public void listenTo(Object source) throws IntrospectionException, IllegalAccessException, InvocationTargetException {
    BeanInfo beanInfo = Introspector.getBeanInfo(source.getClass());
    EventListener listener = getListener(source, beanInfo); 
    for (EventSetDescriptor d : beanInfo.getEventSetDescriptors()) {
      d.getAddListenerMethod().invoke(source, new Object[] { listener });
    }
  }
}
